#ifndef HERM_MSG_DECODER_H
#define HERM_MSG_DECODER_H

//#include "herm/base/utils.h"
#include "msg_base.h"

namespace herm{
class HERM_API DefHdrDecoder : public Decoder
{
public:
	DefHdrDecoder(const char* buf, int len);
	inline uint32_t Length() const
	{
		return m_len;
	}

	inline uint8_t Version() const
	{
		return m_ver;
	}

	inline uint16_t Type() const
	{
		return m_type;
	}

	inline uint16_t Code() const
	{
		return m_code;
	}

private:
	uint32_t m_len; // Length
	uint8_t m_ver;  // Version
	uint16_t m_type; // Type, Type + Code == Msg Command
	uint16_t m_code; // Code
};

template <class HdrDecoder = DefHdrDecoder>
class Decoder0 : public HdrDecoder
{
public:
	Decoder0(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}
};

template <class Body, class HdrDecoder = DefHdrDecoder>
class Decoder1 : public HdrDecoder
{
public:
	Decoder1(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(Body& body, int sizeType = 0)
	{
		HdrDecoder::DecodeSize(sizeType);
		*(Decoder*)this >> body;
	}
};

template <class Body1, class Body2, class HdrDecoder = DefHdrDecoder>
class Decoder2 : public HdrDecoder
{
public:
	Decoder2(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		int sizeType1 = 0, 
		int sizeType2 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;
	}
};

template <class Body1, class Body2, class Body3, class HdrDecoder = DefHdrDecoder>
class Decoder3 : public HdrDecoder
{
public:
	Decoder3(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;
	}
};

template <class Body1, class Body2, class Body3, class Body4, 
	class HdrDecoder = DefHdrDecoder>
class Decoder4 : public HdrDecoder
{
public:
	Decoder4(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;
	}
};

template <class Body1, class Body2, class Body3, class Body4, class Body5, 
	class HdrDecoder = DefHdrDecoder>
class Decoder5 : public HdrDecoder
{
public:
	Decoder5(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		Body5& body5,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0,
		int sizeType5 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;

		HdrDecoder::DecodeSize(sizeType5);
		decoder >> body5;
	}
};

template <class Body1, class Body2, class Body3, class Body4, class Body5,
	class Body6, class HdrDecoder = DefHdrDecoder>
class Decoder6 : public HdrDecoder
{
public:
	Decoder6(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		Body5& body5,
		Body6& body6,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0,
		int sizeType5 = 0,
		int sizeType6 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;

		HdrDecoder::DecodeSize(sizeType5);
		decoder >> body5;

		HdrDecoder::DecodeSize(sizeType6);
		decoder >> body6;
	}
};

template <class Body1, class Body2, class Body3, class Body4, class Body5,
    class Body6, class Body7, class HdrDecoder = DefHdrDecoder>
class Decoder7 : public HdrDecoder
{
public:
	Decoder7(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		Body5& body5,
		Body6& body6,
		Body7& body7,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0,
		int sizeType5 = 0,
		int sizeType6 = 0,
		int sizeType7 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;

		HdrDecoder::DecodeSize(sizeType5);
		decoder >> body5;

		HdrDecoder::DecodeSize(sizeType6);
		decoder >> body6;

		HdrDecoder::DecodeSize(sizeType7);
		decoder >> body7;
	}
};

template <class Body1, class Body2, class Body3, class Body4, class Body5,
	class Body6, class Body7, class Body8, class HdrDecoder = DefHdrDecoder>
class Decoder9 : public HdrDecoder
{
public:
	Decoder9(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		Body5& body5,
		Body6& body6,
		Body7& body7,
		Body8& body8,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0,
		int sizeType5 = 0,
		int sizeType6 = 0,
		int sizeType7 = 0,
		int sizeType8 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;

		HdrDecoder::DecodeSize(sizeType5);
		decoder >> body5;

		HdrDecoder::DecodeSize(sizeType6);
		decoder >> body6;

		HdrDecoder::DecodeSize(sizeType7);
		decoder >> body7;

		HdrDecoder::DecodeSize(sizeType8);
		decoder >> body8;
	}
};

template <class Body1, class Body2, class Body3, class Body4, class Body5,
	class Body6, class Body7, class Body8, class Body9, class HdrDecoder = DefHdrDecoder>
class Decoder8 : public HdrDecoder
{
public:
	Decoder8(const char* buf, int len) : HdrDecoder(buf, len)
	{
	}

	void Decode(
		Body1& body1,
		Body2& body2, 
		Body3& body3, 
		Body4& body4,
		Body5& body5,
		Body6& body6,
		Body7& body7,
		Body8& body8,
		Body9& body9,
		int sizeType1 = 0, 
		int sizeType2 = 0,
		int sizeType3 = 0,
		int sizeType4 = 0,
		int sizeType5 = 0,
		int sizeType6 = 0,
		int sizeType7 = 0,
		int sizeType8 = 0, 
		int sizeType9 = 0)
	{
		Decoder& decoder = *(Decoder*)this;

		HdrDecoder::DecodeSize(sizeType1);
		decoder >> body1;

		HdrDecoder::DecodeSize(sizeType2);
		decoder >> body2;

		HdrDecoder::DecodeSize(sizeType3);
		decoder >> body3;

		HdrDecoder::DecodeSize(sizeType4);
		decoder >> body4;

		HdrDecoder::DecodeSize(sizeType5);
		decoder >> body5;

		HdrDecoder::DecodeSize(sizeType6);
		decoder >> body6;

		HdrDecoder::DecodeSize(sizeType7);
		decoder >> body7;

		HdrDecoder::DecodeSize(sizeType8);
		decoder >> body8;

		HdrDecoder::DecodeSize(sizeType9);
		decoder >> body9;
	}
};

}

#endif
